package unionFind;

/**
 * @program: play-structure
 * @author: baichen
 * 第一版Union-Find本质就是一个数组
 * 实际上就是在一片连续的内存上进行合并操作，JVM进行了优化
 **/
public class UnionFindOne implements UF {
    private int[] id;   //集合编号，不同的连接有不同的编号

    public UnionFindOne(int size) {
        id = new int[size];
        // 初始化, 每一个id[i]指向自己, 没有合并的元素
        for (int i = 0; i < size; i++)
            id[i] = i;
    }

    @Override
    public int getSize() {
        return id.length;
    }

    // 查找元素p所对应的集合编号
    // O(1)复杂度
    private int find(int p) {
        if (p < 0 || p >= id.length)
            throw new IllegalArgumentException("p is out of bound.");
        return id[p];   //返回p对应的集合编号
    }

    // 查看元素p和元素q是否所属一个集合
    // O(1)复杂度
    @Override
    public boolean isConnected(int p, int q) {
        return find(p) == find(q);
    }

    // 合并元素p和元素q所属的集合，即合并之后的两个元素，他们各自所属的集合也会连接起来，修改其对应的集合编号即可
    // O(n) 复杂度
    @Override
    public void unionElements(int p, int q) {
        //p,q对应的集合编号
        int pID = find(p);
        int qID = find(q);
        //p,q集合编号相同，已经在同个集合了，不用合并
        if (pID == qID) {
            return;
        }
        // 合并过程需要遍历一遍所有元素, 将两个元素的所属集合编号合并
        for (int i = 0; i < id.length; i++) {
            //使两个要合并的元素的集合编号相等，反过来也可以
            //其实就是将id[i]对应的值修改为qID,所以此时pID=qID
            if (id[i] == pID) {
                id[i] = qID;
            }
        }
    }
}
